home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programmer Power Tools
/
Programmer Power Tools.iso
/
turbopas
/
tp_tsr.arc
/
DOS21_0A.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1989-02-11
|
9KB
|
239 lines
{═════════════════════════════ DOS21_0A.PAS ══════════════════════════════}
{ ───────── Turbo 4.0/5.0 stay-resident demonstration program ───────── }
{ Copyright (c) 1989 Richard W. Prescott }
{ This Unit contains the assembly code for the basic interrupt routine, }
{ which is installed automatically by the Unit Initialization code. The }
{ original interrupt vector is stored in the current Code segment, which }
{ simplifies chaining to the original interrupt routine. This routine }
{ traps only function $0A (Buffered Input), chaining to the original }
{ interrupt $21 vector for all other function requests. The assembly }
{ code issues a FAR Call via the Pointer variable PascalCode, which must }
{ be initialized to point to an appropriate interrupt service routine. }
{═════════════════════════════════════════════════════════════════════════}
{ This Unit was compiled and assembled using Turbo Pascal Version 5.0 }
{ and TP&Asm Version 2 ß. TP&Asm provides an integrated compile-time }
{ assembler within the Turbo development environment (and the command }
{ line compiler TPC), resulting in an ASSEMBLY Development Environment }
{ which is identical to your PASCAL Development Environment. }
{ }
{ TP&Asm Version 2.0 will be available from me for $49 plus $3 P&H. The }
{ current Beta Test Version 2 ß is available now for $39 plus $3 P&H, }
{ with a free upgrade to 2.0 when it becomes available. }
{ Please see the README file for further information. }
{═════════════════════════════════════════════════════════════════════════}
Unit DOS21_0A;
INTERFACE
PROCEDURE IRestore;
PROCEDURE IReturn;
PROCEDURE IChain;
TYPE
UserRegs = RECORD
CASE INTEGER OF
0: (Ax,Bx,Cx,Dx,Si,Ds,Di,Es,Bp,Ip,Cs,Flags: WORD);
1: (Al,Ah,Bl,Bh,Cl,Ch,Dl,Dh : BYTE);
END; {UserRegs}
VAR
PascalCode: Pointer;
UserSP,UserSS: WORD;
User: ^UserRegs absolute UserSP;
CONST
CommandSig: WORD = 0;
{═══════════════════════════════ SetSpLow ════════════════════════════════}
{ Simple inline directive used in Shell to insure that "resident" stack }
{ doesn't overlay the Exec Return. }
{═══════════════════════════════ SetSpLow ════════════════════════════════}
PROCEDURE SetSpLow; Asm Mov Sp,$180; {- Inline Directive -}
{═════════════════════════════ DefaultDrive ══════════════════════════════}
{ Returns the default drive as a capital letter. }
{═════════════════════════════ DefaultDrive ══════════════════════════════}
FUNCTION DefaultDrive: CHAR; {- Inline Directive -}
ASSEMBLE
Mov Ah,$19
Int $21
Add Al,$41
END; {Assemble}
{═════════════════════════ FreeEnvironmentBlock ══════════════════════════}
{ Reduces resident memory usage by freeing the environment block for use }
{ by the next process. }
{═════════════════════════ FreeEnvironmentBlock ══════════════════════════}
PROCEDURE FreeEnvironmentBlock; {- Inline Directive -}
ASSEMBLE
Push PrefixSeg
Pop Es
Mov Bx,$2C ;Addr of Environment Seg
Mov Es,Es:[Bx] ;Seg to release
Mov Ah,$49
Int $21
END; {Assemble}
IMPLEMENTATION
CONST
ActiveFlag: BOOLEAN = FALSE;
{════════════════════════════════ CsData ═════════════════════════════════}
{ The CSDATA construct is used to store data in the current Code Segment. }
{ The original interrupt address Dos21Vec MUST be stored in this Code }
{ Segment to allow Chaining to the original interrupt routine with all of }
{ the User Registers intact. (The remaining variables COULD be stored in }
{ the Data Segment and referenced after "Mov Ax,SEG Data" & "Mov Ds,Ax"). }
{ CsData Variables are available throughout the current Unit. }
{════════════════════════════════ CsData ═════════════════════════════════}
CsData
Dos21Vec Dd 0
OurDs Dw 0
OurSs Dw 0
OurSp Dw 0
OurBp Dw 0
END; {CsData}
{═════════════════════════════════ IHook ═════════════════════════════════}
{ This is the assembly portion of the interrupt service routine. }
{ For function requests other than $0A, chain to the original interrupt }
{ using an indirect jump to the address Dos21Vec stored in this Code }
{ Segment. For $0A, save registers, then restore Ds (stored in this Code }
{ Segment) and check ActiveFlag to avoid re-entrancy. If not active, }
{ save user stack frame and restore the Turbo program stack frame. }
{ Finally, issue an indirect call to the address stored in the Pointer }
{ PascalCode. An ordinary return from PascalCode results in an automatic }
{ chain to the original interrupt. (But see also IReturn and IChain). }
{ ── The Pascal code for the Interrupt Service must be a FAR Procedure ── }
{═════════════════════════════════ IHook ═════════════════════════════════}
PROCEDURE IHook; Forward;
Internal Hook;
;- Use INTERNAL to eliminate standard Pascal Startup Code
CODE SEGMENT
IHook Proc Near
Cmp Ah,0A
IF NE Jmp Dos21Vec ;- (TP&Asm generates an automatic Cs override)
Push Bp,Es,Di,Ds,Si,Dx,Cx,Bx,Ax
Mov Ax,Ds ; Store user signature in Ax
Mov Ds,OurDs ; Restore Our Ds
Cmp CommandSig,0 ; First Call is from COMMAND.COM ... Store Signature
IF Z Mov CommandSig,Ax
Cmp ActiveFlag,0 ;NOW check Flag stored in our DS
jNZ Chain
Inc ActiveFlag ; =1 until Resume
Mov UserSS,Ss ; Save User Stack Ss:Sp in Our Ds
Mov UserSP,Sp ; (other registers stored on User Stack)
Mov Ss,OurSs ; Switch to Our Stack Frame
Mov Sp,OurSp
Mov Bp,OurBp
Call PascalCode ; pointer to Pascal Service Routine
Mov Ss,UserSS ; Restore User Stack Ss:Sp From Our Ds
Mov Sp,UserSP
Mov ActiveFlag,0 ; Reset Flag stored in our DS
Chain:
Pop Ax,Bx,Cx,Dx,Si,Ds,Di,Es,Bp ;Restore user registers
Jmp Dos21Vec
IHook ENDP
CODE ENDS
END; {INTERNAL Hook}
{═════════════════════════════════ IInit ═════════════════════════════════}
{ Store Turbo program registers Ds, Ss, Sp, and Bp, and the current value }
{ of the interrupt $21 vector, in the current Code Segment. Set the new }
{ value of the interrupt $21 vector to point to INTERNAL Procedure IHook. }
{═════════════════════════════════ IInit ═════════════════════════════════}
PROCEDURE IInit;
{$S-} BEGIN {$S+} {- Don't generate Stack check code -}
ASSEMBLE
Mov OurDs,Ds
Mov OurSs,Ss
Mov OurSp,Sp
Mov OurBp,Bp
Mov Ax,03521 ; Get Interrupt into Es:Bx
Int 021 ;-Store in Code Seg to allow Chaining
Mov W Dos21Vec,Bx ; This Assembly Reference will link in CsData
Mov W Dos21Vec+2,Es
Mov Ax,02521 ; Set Interrupt to Ds:Dx
Push Cs
Pop Ds
Mov Dx,Offset IHook ; This Assembly Reference will link in IHook
Int 021
Mov Ds,OurDs
END; {Assemble}
END; {PROCEDURE IInit}
{═══════════════════════════════ IRestore ════════════════════════════════}
{ Restore the interrupt $21 vector to the value saved during IInit. See }
{ the Procedure Shell in CMDQ.PAS. }
{═══════════════════════════════ IRestore ════════════════════════════════}
PROCEDURE IRestore;
{$S-} BEGIN {$S+} {- Don't generate Stack check code -}
ASSEMBLE
Mov Ax,02521 ; Set Interrupt to Ds:Dx
Push Ds
Lds Dx,Dos21Vec
Int 021
Pop Ds
END; {Assemble}
END; {IRestore;}
{════════════════════════════════ IReturn ════════════════════════════════}
{ Set Inactive Flag, restore user registers, and return from interrupt. }
{ May be called from within nested procedures. User registers may be }
{ inspected/modified before return via the User^ record (User^.Bx, etc). }
{════════════════════════════════ IReturn ════════════════════════════════}
PROCEDURE IReturn;
{$S-} BEGIN {$S+} {- Don't generate Stack check code -}
ASSEMBLE
Mov Ss,UserSS ;Restore User Stack Ss:Sp From Our Ds
Mov Sp,UserSP
Mov ActiveFlag,0 ;Reset Flag stored in our DS
Pop Ax,Bx,Cx,Dx,Si,Ds,Di,Es,Bp ;Restore user registers
Iret
END; {Assemble}
END; {IReturn;}
{════════════════════════════════ IChain ═════════════════════════════════}
{ Set Inactive Flag, restore user registers, and jump to old interrupt. }
{ May be called from within nested procedures. User registers may be }
{ inspected/modified before chain via the User^ record (User^.Bx, etc). }
{════════════════════════════════ IChain ═════════════════════════════════}
PROCEDURE IChain;
{$S-} BEGIN {$S+} {- Don't generate Stack check code -}
ASSEMBLE
Mov Ss,UserSS ;Restore User Stack Ss:Sp From Our Ds
Mov Sp,UserSP
Mov ActiveFlag,0 ;Reset Flag stored in our DS
Pop Ax,Bx,Cx,Dx,Si,Ds,Di,Es,Bp ;Restore user registers
Jmp Dos21Vec
END; {Assemble}
END; {IChain;}
{═════════════════════════════ Initialiation ═════════════════════════════}
{ Automatically install interrupt system. }
{═════════════════════════════ Initialiation ═════════════════════════════}
BEGIN
IInit;
END.